import { Actor } from '../src/actor/actor';
import { Context } from '../src/actor/context';
import { Props } from '../src/actor/props';
import { PID } from '../src/actor/pid';
import { ActorSystem } from '../src/actor/actorSystem';
import { Remote } from '../src/remote/remote';
import { JsonSerializer } from '../src/remote/serializer';

// 定义一个简单的 Actor
class GreetingActor implements Actor {
  receive(context: Context): void { 
    const message = context.message();
    console.log('GreetingActor received message:', message);
    
    // 处理字符串消息
    if (typeof message === 'string') {
      console.log(`Received greeting: ${message}`);
      const response = `Hello from ${context.self().id} in response to "${message}"`;
      console.log('Sending response:', response);
      context.respond(response);
      return;
    }
    
    // 处理包络消息（对象中包含 message 和 sender）
    if (typeof message === 'object' && message !== null && 'message' in message) {
      const actualMessage = message.message;
      console.log(`Received greeting in envelope: ${actualMessage}`);
      
      // 如果内部消息是字符串，则响应
      if (typeof actualMessage === 'string') {
        const response = `Hello from ${context.self().id} in response to "${actualMessage}"`;
        console.log('Sending response:', response);
        
        // 获取发送者信息
        if ('sender' in message && message.sender) {
          const sender = message.sender;
          console.log(`原始发送者: ${sender.address}/${sender.id}`);
          
          // 使用直接响应，让框架处理PID转换
          console.log(`使用直接响应机制`);
          
          // 我们需要将响应通过远程系统发送回客户端
          try {
            // 获取当前系统的远程组件 - 使用正确的actorSystem()方法
            const system = context.actorSystem();
            console.log(`获取到系统: ${typeof system}`);
            
            // 获取挂载在系统上的remote属性
            const remote = (system as any).remote;
            if (remote) {
              console.log(`获取到远程系统组件，创建响应消息`);
              
              // 将客户端的PID信息包装到响应中
              const remoteResponse = {
                type: 'Response',
                message: response,  // 这是字符串响应
                targetPID: sender,
                // 添加更多元数据，以供Future正确处理
                messageData: {
                  from: context.self().toString(),  // 发送者信息
                  messageType: 'string',
                  content: response
                }
              };
              
              // 获取客户端地址信息（从local转换为实际网络地址）
              const clientAddress = "127.0.0.1:12101";  // 客户端地址是12101
              
              console.log(`准备发送响应到客户端: ${clientAddress}, future ID: ${sender.id}`);
              
              // 使用远程组件发送响应
              remote.endpointManager.sendMessage(clientAddress, remoteResponse)
                .then(() => console.log(`响应发送成功`))
                .catch((err: any) => console.error(`响应发送失败:`, err));
            } else {
              console.log(`无法获取远程系统组件，使用常规响应`);
              context.respond(response);
            }
          } catch (err) {
            console.error(`发送响应时出错:`, err);
            context.respond(response);
          }
        } else {
          // 普通响应
          context.respond(response);
        }
      }
    }
  }
}

async function runServer() {
  // 创建服务器端 Actor 系统
  const serverSystem = new ActorSystem();
  const serverRemote = new Remote(serverSystem);

  // 配置序列化器
  serverRemote.withSerializer(new JsonSerializer());

  // 启动远程处理
  const serverPort = 12100;
  await serverRemote.start('127.0.0.1', serverPort);
  console.log(`Server started on 127.0.0.1:${serverPort}`);

  // 将远程系统添加到 ActorSystem 以便 Actor 可以访问
  (serverSystem as any).remote = serverRemote;
  console.log('Remote system attached to ActorSystem');
  
  // 打印服务器系统中注册的所有PID
  const registry = (serverSystem.processRegistry as any)._processes;
  console.log("服务器系统中注册的所有PID:");
  if (registry) {
    registry.forEach((_: any, key: string) => console.log(`  - ${key}`));
  }

  // 注册可远程激活的 Actor
  serverRemote.register('greeting', new Props(() => new GreetingActor()));
  console.log('Registered GreetingActor');

  return serverSystem;
}

async function runClient() {
  // 创建客户端 Actor 系统
  const clientSystem = new ActorSystem();
  const clientRemote = new Remote(clientSystem);

  // 配置序列化器
  clientRemote.withSerializer(new JsonSerializer());

  // 启动远程处理（使用一个具体的端口而不是随机端口）
  const clientPort = 12101;
  await clientRemote.start('127.0.0.1', clientPort);
  console.log(`Client started on 127.0.0.1:${clientPort}`);
  
  // 将远程系统添加到 ActorSystem 以便访问
  (clientSystem as any).remote = clientRemote;
  console.log('Remote system attached to client ActorSystem');
  
  // 打印客户端系统中注册的所有PID
  const registry = (clientSystem.processRegistry as any)._processes;
  console.log("客户端系统中注册的所有PID:");
  if (registry) {
    registry.forEach((_: any, key: string) => console.log(`  - ${key}`));
  }

  // 获取远程 Actor 引用
  const serverPort = 12100;
  const serverAddress = `127.0.0.1:${serverPort}`;
  console.log('Connecting to server at:', serverAddress);
  const remotePid = clientRemote.activatorForAddress(serverAddress);
  console.log('Got remote PID:', remotePid);

  // 发送消息并等待响应
  try {
    console.log('Sending message to remote actor...');
    const future = clientSystem.root.requestFuture(remotePid, 'Hi from client!', 10000);
    console.log('Waiting for response...');
    const response = await future.wait();
    console.log('Received response:', response);
  } catch (error) {
    console.error('Error sending message:', error);
  }

  return clientSystem;
}

async function main() {
  try {
    // 启动服务器
    console.log('Starting server...');
    const serverSystem = await runServer();
    console.log('Server is running...');

    // 等待服务器启动
    const startupDelay = 2000; // 增加启动延迟到 2 秒
    console.log(`Waiting ${startupDelay}ms for server to initialize...`);
    await new Promise(resolve => setTimeout(resolve, startupDelay));

    // 启动客户端
    console.log('Starting client...');
    const clientSystem = await runClient();
    console.log('Client completed communication');

    // 等待一段时间以确保消息处理完成
    console.log('Waiting for message processing to complete...');
    await new Promise(resolve => setTimeout(resolve, 1000));

    // 清理资源
    console.log('Cleaning up...');
    await Promise.all([
      serverSystem.terminate(),
      clientSystem.terminate()
    ]);

    console.log('Systems terminated');
  } catch (error) {
    console.error('Error:', error);
  }
}

// 运行示例
main().catch(console.error); 